package io.github.talelin.latticy.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.github.talelin.latticy.mapper.AcceptMapper;
import io.github.talelin.latticy.mapper.SerialNumberMapper;
import io.github.talelin.latticy.model.SerialNumberDO;
import io.github.talelin.latticy.service.AcceptService;
import io.github.talelin.latticy.dto.accept.CreateOrUpdateAcceptDTO;
import io.github.talelin.latticy.model.AcceptDO;

import java.sql.Wrapper;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import io.github.talelin.latticy.service.MaintenanceService;
import io.github.talelin.latticy.utils.AcceptUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

/**
 * @author vvboy
 */
@Service
public class AcceptServiceImpl implements AcceptService {

    @Autowired
    private AcceptMapper acceptMapper;
    @Autowired
    private SerialNumberMapper serialNumberMapper;

    @Autowired
    private MaintenanceServiceImpl maintenanceService;

    private final ReentrantLock lock = new ReentrantLock();

    @Override
    public boolean createAccept(CreateOrUpdateAcceptDTO validator) {
        AcceptDO accept = new AcceptDO();
        BeanUtils.copyProperties(validator, accept);

        accept.setId(null);
        accept.setOrderNumber(null);
        accept.setOrderTime(new Date());
        accept.setStatus("0");

        LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
        LocalDateTime todayEnd = todayStart.plusDays(1).minusNanos(1);
        List<SerialNumberDO> serialNumberDOList = serialNumberMapper.selectList(Wrappers.<SerialNumberDO>lambdaQuery()
                .eq(SerialNumberDO::getName, "accept")
                .orderByDesc(SerialNumberDO::getCreateTime));

        Integer index = 0;
        if (CollectionUtils.isEmpty(serialNumberDOList)) {
            SerialNumberDO serialNumberDO = new SerialNumberDO();
            serialNumberDO.setName("accept");
            serialNumberDO.setNumber(0);
            serialNumberMapper.insert(serialNumberDO);
        }

        lock.lock();
        try {
            SerialNumberDO serialNumberDO = serialNumberDOList.get(0);
            // 只有当天 且 不是0的情况，number才会算数，否则都是0
            if (DateUtil.isSameDay(new Date(), serialNumberDO.getUpdateTime())
                    && serialNumberDO.getNumber() != 0) {
                index = serialNumberDO.getNumber();
            }
            index += 1;
            String seq = DateUtil.format(new Date(), "yyyyMMdd");
            seq = seq + (index <= 999 ? String.format("%04d", index) : String.valueOf(index));
            serialNumberDO.setNumber(index);
            serialNumberDO.setUpdateTime(new Date());
            serialNumberMapper.updateById(serialNumberDO);

            accept.setOrderNumber(seq);
            return acceptMapper.insert(accept) > 0;
        } finally {
            lock.unlock();
        }
    }


    @Override
    public boolean updateAccept(AcceptDO accept, CreateOrUpdateAcceptDTO validator) {
        BeanUtils.copyProperties(validator, accept);
        return acceptMapper.updateById(accept) > 0;
    }

    @Override
    public AcceptDO getById(Integer id) {
        return acceptMapper.selectById(id);
    }

    @Override
    public List<AcceptDO> findAll() {
        return acceptMapper.selectList(null);
    }

    @Override
    public boolean deleteById(Integer id) {
        return acceptMapper.deleteById(id) > 0;
    }

    @Override
    public List<AcceptDO> query(QueryWrapper<AcceptDO> queryWrapper) {
        List<AcceptDO> acceptDOS = acceptMapper.selectList(queryWrapper);
        return acceptDOS;
    }

    @Override
    public List<String> statCurMonth() {

        List<Integer> resInt = new ArrayList<>();
        int monthDays = DateUtil.lengthOfMonth(DateUtil.thisMonth() + 1, DateUtil.isLeapYear(DateUtil.thisYear()));
        for (int i = 0; i < monthDays; i++) {
            resInt.add(0);
        }

        List<AcceptDO> acceptDOS = acceptMapper.selectList(Wrappers
                .<AcceptDO>lambdaQuery()
                .between(AcceptDO::getCreateTime,
                        DateUtil.beginOfMonth(new Date()),
                        DateUtil.endOfMonth(new Date())));

        for (AcceptDO acceptDO : acceptDOS) {
            Date createTime = acceptDO.getCreateTime();
            int i = DateUtil.dayOfMonth(createTime);
            resInt.set(i - 1, resInt.get(i - 1) + 1);
        }

        return resInt.stream().map(String::valueOf).collect(Collectors.toList());
    }

    @Override
    public List<String> statLastMonth() {

        DateTime lastMonthDate = DateUtil.lastMonth();

        // 0->
        int lastMonth = DateUtil.month(lastMonthDate);
        int year = DateUtil.thisYear();
        // 如果上个月是11，说明上个月是12月，是去年，年份-1
        if (lastMonth == 11) {
            year--;
        }

        List<Integer> resInt = new ArrayList<>();
        int monthDays = DateUtil.lengthOfMonth(lastMonth + 1,
                DateUtil.isLeapYear(year));
        for (int i = 0; i < monthDays; i++) {
            resInt.add(0);
        }

        List<AcceptDO> acceptDOS = acceptMapper.selectList(Wrappers
                .<AcceptDO>lambdaQuery()
                .between(AcceptDO::getCreateTime,
                        DateUtil.beginOfMonth(lastMonthDate),
                        DateUtil.endOfMonth(lastMonthDate)));

        for (AcceptDO acceptDO : acceptDOS) {
            Date createTime = acceptDO.getCreateTime();
            int i = DateUtil.dayOfMonth(createTime);
            resInt.set(i - 1, resInt.get(i - 1) + 1);
        }

        return resInt.stream().map(String::valueOf).collect(Collectors.toList());
    }

    @Override
    public List<Integer> statCurRatio() {
        Date date = new Date();
        List<AcceptDO> acceptDOS = acceptMapper.selectList(Wrappers
                .<AcceptDO>lambdaQuery()
                .between(AcceptDO::getCreateTime,
                        DateUtil.beginOfMonth(date),
                        DateUtil.endOfMonth(date)));
        Integer i = maintenanceService.curMonthAcceptCount();
        List<Integer> res = new ArrayList<>();
        res.add(i);
        res.add(acceptDOS.size()-i);

        return res;
    }

    @Override
    public List<String> statCurYear() {
        List<Integer> resInt = new ArrayList<>();
        for (int i = 0; i < 12; i++) {
            resInt.add(0);
        }

        List<AcceptDO> acceptDOS = acceptMapper.selectList(Wrappers
                .<AcceptDO>lambdaQuery()
                .between(AcceptDO::getCreateTime,
                        DateUtil.beginOfYear(new Date()),
                        DateUtil.endOfYear(new Date())));

        for (AcceptDO acceptDO : acceptDOS) {
            Date createTime = acceptDO.getCreateTime();
            int i = DateUtil.month(createTime);
            resInt.set(i, resInt.get(i) + 1);
        }

        return resInt.stream().map(String::valueOf).collect(Collectors.toList());
    }

    public static void main(String[] args) {

        int i = DateUtil.dayOfMonth(new Date());
        int thisYear = DateUtil.thisYear();
        int monthDays = DateUtil.lengthOfMonth(DateUtil.thisMonth() + 1, DateUtil.isLeapYear(DateUtil.thisYear()));
        System.out.println(thisYear);
        System.out.println(DateUtil.thisMonth());
        System.out.println(monthDays);
        System.out.println(i);

        System.out.println(DateUtil.month(new Date()));
    }
}
